import os
import pdfplumber
from openpyxl import Workbook
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
from pathlib import Path


class PDFToExcelConverter:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("PDF表格转Excel工具")
        self.root.geometry("600x500")
        self.root.resizable(True, True)
        
        # 配置网格权重，使界面可以自适应调整
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        
        self.setup_ui()
        
    def setup_ui(self):
        """设置用户界面"""
        # 创建主容器
        main_container = ttk.Frame(self.root)
        main_container.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
        main_container.columnconfigure(0, weight=1)
        
        # 标题区域
        title_frame = ttk.Frame(main_container)
        title_frame.grid(row=0, column=0, sticky="ew", pady=(0, 15))
        title_frame.columnconfigure(0, weight=1)
        
        title_label = ttk.Label(title_frame, text="PDF表格转Excel工具", 
                               font=("微软雅黑", 16, "bold"))
        title_label.grid(row=0, column=0)
        
        # 文件夹选择区域
        folder_frame = ttk.LabelFrame(main_container, text="文件夹选择", padding="10")
        folder_frame.grid(row=1, column=0, sticky="ew", pady=(0, 10))
        folder_frame.columnconfigure(1, weight=1)
        
        ttk.Label(folder_frame, text="选择文件夹:").grid(row=0, column=0, sticky="w", padx=(0, 10))
        
        self.folder_var = tk.StringVar()
        folder_entry = ttk.Entry(folder_frame, textvariable=self.folder_var)
        folder_entry.grid(row=0, column=1, sticky="ew", padx=(0, 10))
        
        browse_btn = ttk.Button(folder_frame, text="浏览", command=self.select_folder)
        browse_btn.grid(row=0, column=2)
        
        # 控制按钮区域
        control_frame = ttk.Frame(main_container)
        control_frame.grid(row=2, column=0, sticky="ew", pady=(0, 15))
        control_frame.columnconfigure(0, weight=1)
        
        self.convert_btn = ttk.Button(control_frame, text="开始转换", 
                                     command=self.start_conversion, width=20)
        self.convert_btn.grid(row=0, column=0)
        
        # 进度显示区域
        progress_frame = ttk.LabelFrame(main_container, text="转换进度", padding="10")
        progress_frame.grid(row=3, column=0, sticky="ew", pady=(0, 10))
        progress_frame.columnconfigure(0, weight=1)
        
        self.progress = ttk.Progressbar(progress_frame, mode='determinate')
        self.progress.grid(row=0, column=0, sticky="ew", pady=(0, 5))
        
        self.status_label = ttk.Label(progress_frame, text="请选择包含PDF文件的文件夹")
        self.status_label.grid(row=1, column=0, sticky="w")
        
        # 日志显示区域
        log_frame = ttk.LabelFrame(main_container, text="转换日志", padding="10")
        log_frame.grid(row=4, column=0, sticky="nsew", pady=(0, 0))
        log_frame.columnconfigure(0, weight=1)
        log_frame.rowconfigure(0, weight=1)
        main_container.rowconfigure(4, weight=1)  # 让日志区域可以扩展
        
        # 创建文本框和滚动条的容器
        text_container = ttk.Frame(log_frame)
        text_container.grid(row=0, column=0, sticky="nsew")
        text_container.columnconfigure(0, weight=1)
        text_container.rowconfigure(0, weight=1)
        
        self.log_text = tk.Text(text_container, height=12, wrap=tk.WORD, 
                               font=("Consolas", 9))
        self.log_text.grid(row=0, column=0, sticky="nsew")
        
        # 垂直滚动条
        v_scrollbar = ttk.Scrollbar(text_container, orient="vertical", 
                                   command=self.log_text.yview)
        v_scrollbar.grid(row=0, column=1, sticky="ns")
        self.log_text.configure(yscrollcommand=v_scrollbar.set)
        
        # 水平滚动条
        h_scrollbar = ttk.Scrollbar(text_container, orient="horizontal", 
                                   command=self.log_text.xview)
        h_scrollbar.grid(row=1, column=0, sticky="ew")
        self.log_text.configure(xscrollcommand=h_scrollbar.set)
        
        # 清空日志按钮
        clear_btn = ttk.Button(log_frame, text="清空日志", command=self.clear_log)
        clear_btn.grid(row=1, column=0, sticky="e", pady=(5, 0))
        
    def select_folder(self):
        """选择文件夹"""
        folder_path = filedialog.askdirectory(title="选择包含PDF文件的文件夹")
        if folder_path:
            self.folder_var.set(folder_path)
            self.log_message(f"已选择文件夹: {folder_path}")
            self.status_label.config(text="已选择文件夹，点击开始转换")
            
    def log_message(self, message):
        """添加日志消息"""
        self.log_text.insert(tk.END, f"{message}\n")
        self.log_text.see(tk.END)
        self.root.update_idletasks()
        
    def clear_log(self):
        """清空日志"""
        self.log_text.delete(1.0, tk.END)
        
    def start_conversion(self):
        """开始转换（在新线程中运行）"""
        folder_path = self.folder_var.get().strip()
        if not folder_path:
            messagebox.showwarning("警告", "请先选择文件夹！")
            return
            
        if not os.path.exists(folder_path):
            messagebox.showerror("错误", "选择的文件夹不存在！")
            return
            
        # 在新线程中运行转换，避免界面卡死
        self.convert_btn.config(state='disabled', text="转换中...")
        self.clear_log()
        thread = threading.Thread(target=self.batch_convert_pdfs_in_folder, args=(folder_path,))
        thread.daemon = True
        thread.start()

    def extract_tables_to_excel(self, pdf_path, output_excel_path):
        """提取PDF表格到Excel"""
        try:
            wb = Workbook()
            wb.remove(wb.active)
            table_found = False

            with pdfplumber.open(pdf_path) as pdf:
                for page_index, page in enumerate(pdf.pages):
                    # 尝试不同的提取策略
                    strategies = [
                        {
                            "vertical_strategy": "lines",
                            "horizontal_strategy": "lines",
                            "snap_x_tolerance": 3,
                            "snap_y_tolerance": 3,
                            "join_x_tolerance": 3,
                            "join_y_tolerance": 3,
                            "intersection_x_tolerance": 3
                        },
                        {
                            "vertical_strategy": "text",
                            "horizontal_strategy": "text",
                        }
                    ]
                    
                    tables = []
                    for strategy in strategies:
                        tables = page.extract_tables(strategy)
                        if tables:
                            break

                    if tables:
                        table_found = True
                        ws = wb.create_sheet(title=f"第{page_index + 1}页")

                        current_row = 1
                        for table_index, table in enumerate(tables):
                            # 如果一页有多个表格，添加分隔
                            if table_index > 0:
                                current_row += 2  # 空两行分隔
                                
                            for row_data in table:
                                for col_index, cell in enumerate(row_data):
                                    cleaned_cell = cell.strip() if cell else ""
                                    ws.cell(row=current_row, column=col_index + 1, value=cleaned_cell)
                                current_row += 1

            if table_found:
                wb.save(output_excel_path)
                return True
            else:
                self.log_message(f"  ⚠️ 警告: {Path(pdf_path).name} 中未找到表格")
                return False
                
        except Exception as e:
            self.log_message(f"  ❌ 错误: 处理 {Path(pdf_path).name} 时出错: {str(e)}")
            return False

    def batch_convert_pdfs_in_folder(self, folder_path):
        """批量转换文件夹中的PDF文件"""
        try:
            self.log_message("🔍 开始扫描PDF文件...")
            self.status_label.config(text="正在扫描PDF文件...")
            
            # 获取所有PDF文件
            pdf_files = [f for f in os.listdir(folder_path) 
                        if f.lower().endswith(".pdf") and not f.startswith("~")]

            if not pdf_files:
                self.status_label.config(text="未找到PDF文件")
                self.log_message("❌ 在选定文件夹中未找到任何PDF文件")
                messagebox.showinfo("提示", "在选定文件夹中未找到任何PDF文件。")
                return

            total_files = len(pdf_files)
            self.log_message(f"📁 找到 {total_files} 个PDF文件")
            self.progress['maximum'] = total_files
            self.progress['value'] = 0
            
            success_count = 0
            
            for index, filename in enumerate(pdf_files):
                self.status_label.config(text=f"正在处理: {filename}")
                self.log_message(f"\n📄 正在处理 ({index + 1}/{total_files}): {filename}")
                
                # 构建文件路径
                pdf_path = os.path.join(folder_path, filename)
                excel_filename = os.path.splitext(filename)[0] + ".xlsx"
                output_excel_path = os.path.join(folder_path, excel_filename)

                # 检查输出文件是否已存在
                if os.path.exists(output_excel_path):
                    self.log_message(f"  ⚠️ 文件已存在，将覆盖: {excel_filename}")

                # 转换文件
                if self.extract_tables_to_excel(pdf_path, output_excel_path):
                    success_count += 1
                    self.log_message(f"  ✅ 成功: {filename} -> {excel_filename}")
                
                # 更新进度条
                self.progress['value'] = index + 1
                self.root.update_idletasks()

            # 完成处理
            self.status_label.config(text=f"转换完成! 成功: {success_count}/{total_files}")
            self.log_message(f"\n🎉 转换完成! 成功转换 {success_count} 个文件，共 {total_files} 个文件")
            
            if success_count > 0:
                messagebox.showinfo("完成", 
                    f"转换完成!\n✅ 成功: {success_count} 个文件\n📊 总计: {total_files} 个文件\n\n文件保存在: {folder_path}")
            else:
                messagebox.showwarning("警告", "没有成功转换任何文件，请检查PDF文件是否包含表格。")

        except Exception as e:
            error_msg = f"处理过程中发生错误：{str(e)}"
            self.log_message(f"❌ 错误: {error_msg}")
            self.status_label.config(text="处理出错")
            messagebox.showerror("错误", error_msg)
        finally:
            self.convert_btn.config(state='normal', text="开始转换")
            if self.progress['value'] == 0:
                self.progress['value'] = 0

    def run(self):
        """运行应用程序"""
        # 添加关闭窗口时的确认
        def on_closing():
            if messagebox.askokcancel("退出", "确定要退出程序吗？"):
                self.root.destroy()
        
        self.root.protocol("WM_DELETE_WINDOW", on_closing)
        
        # 初始日志
        self.log_message("📋 PDF表格转Excel工具已启动")
        self.log_message("💡 请选择包含PDF文件的文件夹，然后点击开始转换")
        
        self.root.mainloop()


if __name__ == "__main__":
    app = PDFToExcelConverter()
    app.run()
